package com.harmony.pilot.knowledge.service;

import com.harmony.pilot.knowledge.entity.CallRelation;
import com.harmony.pilot.knowledge.repository.CallRelationRepository;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 调用链服务
 * 提供函数调用链查询功能
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CallChainService {
    
    private final CallRelationRepository callRelationRepository;
    
    /**
     * 查找从startFunction到endFunction的调用链
     * 使用广度优先搜索（BFS）
     */
    public List<CallChainResult> findCallChain(String startFunction, String endFunction, int maxDepth) {
        List<CallChainResult> results = new ArrayList<>();
        
        // BFS队列
        Queue<CallPathNode> queue = new LinkedList<>();
        queue.offer(new CallPathNode(startFunction, new ArrayList<>(Arrays.asList(startFunction)), 0));
        
        // 访问过的节点（避免循环）
        Set<String> visited = new HashSet<>();
        visited.add(startFunction);
        
        while (!queue.isEmpty()) {
            CallPathNode current = queue.poll();
            
            // 达到最大深度
            if (current.getDepth() >= maxDepth) {
                continue;
            }
            
            // 查找当前函数调用的所有函数
            List<CallRelation> relations = callRelationRepository.findByCallerName(current.getFunctionName());
            
            for (CallRelation relation : relations) {
                String callee = relation.getCalleeName();
                
                // 创建新路径
                List<String> newPath = new ArrayList<>(current.getPath());
                newPath.add(callee);
                
                // 找到目标函数
                if (callee.equals(endFunction)) {
                    CallChainResult result = new CallChainResult();
                    result.setPath(newPath);
                    result.setDepth(current.getDepth() + 1);
                    result.setRelations(buildRelationChain(newPath));
                    results.add(result);
                    continue;
                }
                
                // 避免循环调用
                if (!visited.contains(callee)) {
                    visited.add(callee);
                    queue.offer(new CallPathNode(callee, newPath, current.getDepth() + 1));
                }
            }
        }
        
        return results;
    }
    
    /**
     * 查找所有调用该函数的函数（反向查询）
     */
    public List<CallerInfo> findCallers(String functionName, int maxDepth) {
        List<CallerInfo> callers = new ArrayList<>();
        Set<String> visited = new HashSet<>();
        
        findCallersRecursive(functionName, 1, maxDepth, visited, callers);
        
        return callers;
    }
    
    /**
     * 递归查找调用者
     */
    private void findCallersRecursive(String functionName, int currentDepth, int maxDepth,
                                      Set<String> visited, List<CallerInfo> result) {
        if (currentDepth > maxDepth || visited.contains(functionName)) {
            return;
        }
        
        visited.add(functionName);
        
        // 查找直接调用者
        List<CallRelation> relations = callRelationRepository.findByCalleeName(functionName);
        
        for (CallRelation relation : relations) {
            String caller = relation.getCallerName();
            
            CallerInfo info = new CallerInfo();
            info.setName(caller);
            info.setFile(relation.getCallerFile());
            info.setRepo(relation.getCallerRepo());
            info.setDepth(currentDepth);
            info.setDirect(currentDepth == 1);
            info.setLine(relation.getCallLine());
            info.setCrossRepo(relation.getIsCrossRepo());
            info.setInnerAPI(relation.getIsInnerAPI());
            
            result.add(info);
            
            // 递归查找调用者的调用者
            findCallersRecursive(caller, currentDepth + 1, maxDepth, visited, result);
        }
    }
    
    /**
     * 查找跨仓调用
     */
    public List<CrossRepoCallInfo> findCrossRepoCalls(String repo) {
        List<CallRelation> relations = callRelationRepository.findCrossRepoCallsByRepo(repo);
        
        List<CrossRepoCallInfo> results = new ArrayList<>();
        for (CallRelation relation : relations) {
            CrossRepoCallInfo info = new CrossRepoCallInfo();
            info.setCallerName(relation.getCallerName());
            info.setCallerFile(relation.getCallerFile());
            info.setCallerRepo(relation.getCallerRepo());
            info.setCalleeName(relation.getCalleeName());
            info.setCalleeRepo(relation.getCalleeRepo());
            info.setIsInnerAPI(relation.getIsInnerAPI());
            info.setDeclaredIn(relation.getDeclaredIn());
            info.setLine(relation.getCallLine());
            
            results.add(info);
        }
        
        return results;
    }
    
    /**
     * 构建关系链
     */
    private List<CallRelation> buildRelationChain(List<String> path) {
        List<CallRelation> chain = new ArrayList<>();
        
        for (int i = 0; i < path.size() - 1; i++) {
            String caller = path.get(i);
            String callee = path.get(i + 1);
            
            List<CallRelation> relations = callRelationRepository.findByCallerName(caller);
            for (CallRelation relation : relations) {
                if (relation.getCalleeName().equals(callee)) {
                    chain.add(relation);
                    break;
                }
            }
        }
        
        return chain;
    }
    
    /**
     * 内部类：调用路径节点
     */
    @Data
    private static class CallPathNode {
        private String functionName;
        private List<String> path;
        private int depth;
        
        public CallPathNode(String functionName, List<String> path, int depth) {
            this.functionName = functionName;
            this.path = path;
            this.depth = depth;
        }
    }
    
    /**
     * 调用链结果
     */
    @Data
    public static class CallChainResult {
        private List<String> path;            // 调用路径
        private int depth;                    // 深度
        private List<CallRelation> relations; // 详细关系
    }
    
    /**
     * 调用者信息
     */
    @Data
    public static class CallerInfo {
        private String name;        // 函数名
        private String file;        // 文件路径
        private String repo;        // 仓库
        private int depth;          // 调用深度
        private boolean direct;     // 是否直接调用
        private Integer line;       // 调用行号
        private Boolean crossRepo;  // 是否跨仓
        private Boolean innerAPI;   // 是否inner API
    }
    
    /**
     * 跨仓调用信息
     */
    @Data
    public static class CrossRepoCallInfo {
        private String callerName;
        private String callerFile;
        private String callerRepo;
        private String calleeName;
        private String calleeRepo;
        private Boolean isInnerAPI;
        private String declaredIn;
        private Integer line;
    }
}

